package com.tianyu.inspection.service;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tianyu.inspection.common.Constants;
import com.tianyu.inspection.common.enums.RoState;
import com.tianyu.inspection.common.enums.WebSocketMessageType;
import com.tianyu.inspection.entity.Pipeline;
import com.tianyu.inspection.common.enums.FileTypeEnum;
import com.tianyu.inspection.common.model.PageModel;
import com.tianyu.inspection.entity.vo.WebSocketRo;
import com.tianyu.inspection.service.api.IPipelineService;
import com.tianyu.inspection.common.component.AppConstants;
import com.tianyu.inspection.entity.PipelinePoint;
import com.tianyu.inspection.entity.UploadFile;
import com.tianyu.inspection.entity.model.OperateMo;
import com.tianyu.inspection.entity.model.QueryMo;
import com.tianyu.inspection.entity.vo.Point;
import com.tianyu.inspection.mapper.PipelineMapper;
import com.tianyu.inspection.mapper.PipelinePointMapper;
import com.tianyu.inspection.mapper.UploadFileMapper;
import com.tianyu.inspection.service.websocket.WebSocketService;
import io.ocs.common.OcsConstants;
import io.ocs.model.OcsObject;
import io.ocs.model.OcsSimpleModel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.tianyu.inspection.common.Constants.GLOBAL_LOCK_MAP;

/**********************************
 * @Author YSW
 * @Description 管线服务
 * @Date 2021/1/18 - 09:38
 **********************************/

@Slf4j
@Service
public class PipelineServiceImpl implements IPipelineService {

    @Resource
    private PipelineMapper pipelineMapper;

    @Resource
    private PipelinePointMapper pipelinePointMapper;

    @Resource
    private OcsSimpleModel ocsSimpleModel;

    @Resource
    private AppConstants appConstants;

    @Resource
    private OcsConstants ocsConstants;

    @Resource
    private UploadFileMapper uploadFileMapper;

    @Resource
    private ValueOperations<String, Object> valueOperations;

    @Resource
    private SetOperations<String, Object> setOperations;

    @Override
    public IPage<Pipeline> getDbPipelineList(QueryMo queryMo) {
        IPage<Pipeline> pipelineList = searchListPage(queryMo);
        List<Pipeline> pipelines = pipelineList.getRecords();
        if (cachePipeline(pipelines) != pipelines.size()) {
            pipelines.forEach(pipeline -> {
                Integer pipelineId = pipeline.getId();
                QueryMo queryMo1 = new QueryMo();
                queryMo1.put("pipelineId", pipelineId);
                queryMo1.build(PipelinePoint.class, null);
                List<PipelinePoint> pipelinePoints = pipelinePointMapper.selectList(new QueryWrapper<PipelinePoint>().allEq(queryMo1.getEqMap()));
                pipeline.setPoints(pipelinePoints);
                pipeline.setPointsUrl(null);
                pipeline.setPointsCount(pipelinePoints.size());
                String redisKey = appConstants.redisPipeline + pipeline.getProjectId() + ":" + pipeline.getName() + "[" + pipeline.getId() + "]";
                valueOperations.set(redisKey, pipelinePoints, 7, TimeUnit.DAYS);
                setOperations.add(appConstants.redisPipeline + pipeline.getProjectId(), redisKey);
            });
        }
        return pipelineList;
    }

    private Integer cachePipeline(List<Pipeline> pipelines) {
        AtomicInteger count = new AtomicInteger();
        pipelines.forEach(pipeline -> {
            String redisKey = appConstants.redisPipeline + pipeline.getProjectId() + ":" + pipeline.getName() + "[" + pipeline.getId() + "]";
            Object object = valueOperations.get(redisKey);
            if (Objects.nonNull(object)) {
                pipeline.setPoints(object);
                JSONArray jsonArray = new ObjectMapper().convertValue(object, JSONArray.class);
                pipeline.setPointsCount(jsonArray.size());
                pipeline.setPointsUrl(null);
                count.getAndIncrement();
            }
        });
        return count.get();
    }

    @Override
    public IPage<Pipeline> getOssPipelineList(QueryMo queryMo) {
        IPage<Pipeline> pipelineList = searchListPage(queryMo);
        List<Pipeline> pipelines = pipelineList.getRecords();
        pipelines.forEach(pipeline -> {
            String ossUrl = pipeline.getPointsUrl();
            try {
                OcsObject cosObject = ocsSimpleModel.getUrlObject(ossUrl);
                if (Objects.nonNull(cosObject)) {
                    com.tianyu.inspection.common.protobuf.Pipeline.DataList dataList =
                            com.tianyu.inspection.common.protobuf.Pipeline.DataList.parseFrom(cosObject.getInputStream());
                    List<com.tianyu.inspection.common.protobuf.Pipeline.Point> pointList = dataList.getPointList();
                    List<Point> returnList = new ArrayList<>();
                    pointList.forEach(point -> returnList.add(new Point(point.getLng(), point.getLat(), point.getAlt(), point.getSeq())));
                    pipeline.setPoints(returnList);
                    pipeline.setPointsUrl(null);
                    pipeline.setPointsCount(pointList.size());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        return pipelineList;
    }

    @Override
    public boolean savePipeline(String pipelineName, Integer projectId, List<PipelinePoint> pointList) {
        if (Objects.isNull(pointList) || pointList.size() == 0) {
            return false;
        }
        com.tianyu.inspection.common.protobuf.Pipeline.DataList.Builder dataListBuilder = com.tianyu.inspection.common.protobuf.Pipeline.DataList.newBuilder();
        pointList.forEach(point -> {
            com.tianyu.inspection.common.protobuf.Pipeline.Point.Builder dataBuilder = com.tianyu.inspection.common.protobuf.Pipeline.Point.newBuilder();
            dataBuilder.setLat(point.getLat());
            dataBuilder.setLng(point.getLng());
            if (Objects.nonNull(point.getAlt())) {
                dataBuilder.setAlt(point.getAlt());
            } else {
                dataBuilder.setAlt(0);
            }
            if (Objects.nonNull(point.getSeq())) {
                dataBuilder.setSeq(point.getSeq());
            }
            dataListBuilder.addPoint(dataBuilder.build());
        });
        PipelinePoint centerPoint = pointList.get(pointList.size() / 2);
        dataListBuilder.setCenterLng(centerPoint.getLng());
        dataListBuilder.setCenterLat(centerPoint.getLat());
        String filePath = projectId + "/pipeline/" + System.currentTimeMillis() + ".pb";
        ocsSimpleModel.putObject(filePath, dataListBuilder.build().toByteArray());
        final int available;
        available = Math.toIntExact(ocsSimpleModel.getObject(filePath).getContentLength());
        UploadFile uploadFile = new UploadFile()
                .setUrl("/" + filePath)
                .setProjectId(projectId)
                .setSize((long) available)
                .setType("application/octet-stream")
                .setCategory(FileTypeEnum.FILE_PIPELINE_PB.getValue());
        Pipeline pipeline = new Pipeline()
                .setProjectId(projectId)
                .setPointsUrl("/" + filePath)
                .setCenterPoint("[" + centerPoint.getLng() + "," + centerPoint.getLat() + "]");
        if (Objects.nonNull(pipelineName) && (!Objects.equals(pipelineName, ""))) {
            pipeline.setName(pipelineName);
        } else {
            pipeline.setName("pipeline");
        }
        if ((1 != uploadFileMapper.insert(uploadFile)) || (1 != pipelineMapper.insert(pipeline))) {
            ocsSimpleModel.deleteObject(filePath);
            return false;
        } else {
            return pipelinePointsInsert(pointList, pipeline.getId());
        }
    }

    public boolean pipelinePointsInsert(List<PipelinePoint> pointList, Integer id) {
        pointList.forEach(pipelinePoint -> pipelinePoint.setPipelineId(id));
        return pipelinePointMapper.batchInsert(pointList) == pointList.size();
    }

    /**
     * 分页查询
     *
     * @param queryMo 参数模型
     * @return ModelMap
     */
    @Override
    public IPage<Pipeline> searchListPage(QueryMo queryMo) {
        IPage<Pipeline> modelPage = PageModel.getModelPage(queryMo, pipelineMapper);
        final List<Pipeline> records = modelPage.getRecords();
        records.forEach(pipeline -> {
            String pointsUrl = pipeline.getPointsUrl();
            if (Objects.nonNull(pointsUrl)) {
                pipeline.setPointsUrl(ocsSimpleModel.getObjectUrl(pointsUrl));
            }
        });
        return modelPage;
    }

    @Override
    public List<Pipeline> getLinesTree(QueryMo queryMo) {
        queryMo.setPageNum(1);
        queryMo.setPageSize(-1);
        IPage<Pipeline> modelPage = PageModel.getModelPage(queryMo, pipelineMapper);
        final List<Pipeline> records = modelPage.getRecords();
        Map<Integer, Pipeline> rootMap = new HashMap<>();
        final List<Pipeline> folders = records.stream()
                .filter(pipeline -> pipeline.getType() == 1).collect(Collectors.toList());
        final List<Pipeline> children = records.stream()
                .filter(pipeline -> pipeline.getType() == 0).collect(Collectors.toList());
        for (Pipeline folder : folders) {
            rootMap.put(folder.getId(), folder);
        }
        for (Pipeline pipeline : children) {
            String pointsUrl = pipeline.getPointsUrl();
            if (Objects.nonNull(pointsUrl)) {
                pipeline.setPointsUrl(ocsSimpleModel.getObjectUrl(pointsUrl));
            }
            final Integer parentId = pipeline.getParentId();
            if (parentId != null) {
                final Pipeline folder = rootMap.get(parentId);
                if (folder != null) {
                    folder.getChildren().add(pipeline);
                }
            } else {
                rootMap.put(pipeline.getId(), pipeline);
            }
        }
        setChild(folders, rootMap);
        return new ArrayList<>(rootMap.values());
    }

    private void setChild(List<Pipeline> folders, Map<Integer, Pipeline> folderMap) {
        for (Pipeline folder : folders) {
            final Integer parentId = folder.getParentId();
            if (parentId != null) {
                final List<Pipeline> childFolders = folderMap.values().stream().filter(pipeline -> folder.getId().equals(pipeline.getParentId())).collect(Collectors.toList());
                if (childFolders.size() != 0) {
                    setChild(childFolders, folderMap);
                }
                final Pipeline parentFolder = folderMap.get(parentId);
                if (parentFolder != null) {
                    final List<Pipeline> children = parentFolder.getChildren();
                    if (children.stream().noneMatch(basicInformation -> Objects.equals(basicInformation.getId(), folder.getId()))) {
                        children.add(folder);
                        folderMap.remove(folder.getId());
                    }
                }
            }
        }
    }

    @Override
    public List<Pipeline> getLinesTreeLevel(QueryMo queryMo, String parentId) {
        final JSONObject jsonObject = new JSONObject();
        jsonObject.put("pageSize", -1);
        jsonObject.put("pageNum", 1);
        final JSONObject eqParams = jsonObject.getJSONObject("eqParams");
        final QueryWrapper<Pipeline> wrapper = new QueryWrapper<>();
        if (parentId == null || "-1".equals(parentId)) {
            wrapper.isNull("parent_id");
        } else {
            wrapper.eq("parent_id", parentId);
        }
        IPage<Pipeline> modelPage = PageModel.getModelPage(wrapper, queryMo, pipelineMapper);
        return modelPage.getRecords();
    }

    @Resource
    private WebSocketService webSocketService;

    @Override
    public JSONObject kmlJsonLoadPrepare(JSONObject kmlObject) {
        final JSONObject xml = kmlObject.getJSONObject("kml");
        final JSONObject document = xml.getJSONObject("Document");
        final JSONObject object = JSONObject.parseObject(document.toJSONString());
        AtomicInteger folderCount = new AtomicInteger(0);
        AtomicInteger placemarkCountTotal = new AtomicInteger(0);
        recursionParserObjCount(object, folderCount, placemarkCountTotal);
        log.info("folderCount: {} ,placemarkCount: {}", folderCount, placemarkCountTotal);
        return JSONObject.of("folderCount", folderCount, "placemarkCountTotal", placemarkCountTotal);
    }

    @Override
    public JSONObject kmlObjectLoad(JSONObject kmlObject, Integer projectId, Integer userId) {
        final JSONObject xml = kmlObject.getJSONObject("kml");
        final JSONObject document = xml.getJSONObject("Document");
        final JSONObject object = JSONObject.parseObject(document.toJSONString());
        final JSONObject result = kmlJsonLoadPrepare(kmlObject);
        Integer placemarkCountTotal = result.getInteger("placemarkCountTotal");
        final String kmlLoadLockPrefix = "kmlLoad-";
        Constants.EXECUTOR.execute(() -> {
            final String key = kmlLoadLockPrefix + projectId + "-" + UUID.randomUUID();
            final CountDownLatch countDownLatch1 = new CountDownLatch(1);
            GLOBAL_LOCK_MAP.put(key, countDownLatch1);
            AtomicInteger count = new AtomicInteger(0);
            recursionParserObj(object, null, projectId, userId, placemarkCountTotal, count);
            log.info("load-count: " + count);
            final Optional<Map.Entry<String, CountDownLatch>> first = GLOBAL_LOCK_MAP.entrySet().stream().filter((entity -> entity.getKey().equals(key))).findFirst();
            if (first.isPresent()) {


            }
        });
        return result;
    }


    @Async
    protected void recursionParserObjCount(JSONObject object, AtomicInteger folderCount, AtomicInteger placemarkCount) {
        final Set<Map.Entry<String, Object>> entries = object.entrySet();
        if (object.containsKey("Folder")) {
            folderCount.incrementAndGet();
        }
        for (Map.Entry<String, Object> entry : entries) {
            final String key = entry.getKey();
            final Object value = entry.getValue();
            if ("Folder".equals(key)) {
                if (value instanceof JSONArray) {
                    for (Object value2 : JSONArray.from(value)) {
                        recursionParserObjCount(JSONObject.from(value2), folderCount, placemarkCount);
                    }
                    continue;
                }
                if (value instanceof JSONObject) {
                    recursionParserObjCount(JSONObject.from(value), folderCount, placemarkCount);
                    continue;
                }
            }
            if ("Placemark".equals(key)) {
                if (value instanceof JSONArray) {
                    folderCount.incrementAndGet();
                    final JSONArray placemarks = JSONArray.from(value);
                    for (Object placemark : placemarks) {
                        final JSONObject jsonObject = JSONObject.from(placemark);
                        countPlacemark(jsonObject, placemarkCount);
                    }
                } else {
                    countPlacemark(JSONObject.from(value), placemarkCount);
                }
            }
        }
    }

    private void countPlacemark(JSONObject placemark, AtomicInteger placemarkCount) {
        final JSONObject lineString = placemark.getJSONObject("LineString");
        if (lineString != null) {
            placemarkCount.incrementAndGet();
        }
    }

    private void recursionParserObj(JSONObject object, Integer parentId, Integer projectId, Integer userId, Integer placemarkCountTotal, AtomicInteger count) {
        final Set<Map.Entry<String, Object>> entries = object.entrySet();
        if (object.containsKey("Folder")) {
            final String folderName = object.getString("name");
            log.info(parentId + "-" + folderName);
            final Pipeline basicInformation = Pipeline.builder()
                    .type(1)
                    .name((folderName == null || "".equals(folderName)) ? "未命名Folder" : folderName)
                    .parentId(parentId)
                    .projectId(projectId)
                    .build();
            pipelineMapper.insert(basicInformation);
            parentId = basicInformation.getId();
        }
        for (Map.Entry<String, Object> entry : entries) {
            final String key = entry.getKey();
            final Object value = entry.getValue();
            if ("Folder".equals(key)) {
                if (value instanceof JSONArray) {
                    for (Object value2 : JSONArray.from(value)) {
                        recursionParserObj(JSONObject.from(value2), parentId, projectId, userId, placemarkCountTotal, count);
                    }
                    continue;
                }
                if (value instanceof JSONObject) {
                    recursionParserObj(JSONObject.from(value), parentId, projectId, userId, placemarkCountTotal, count);
                    continue;
                }
            }
            if ("Placemark".equals(key)) {
                if (value instanceof JSONArray) {
                    final String folderName = object.getString("name");
                    log.info(parentId + "-" + folderName);
                    final Pipeline basicInformation = Pipeline.builder()
                            .type(1)
                            .name((folderName == null || "".equals(folderName)) ? "未命名PlacemarkArray" : folderName)
                            .parentId(parentId)
                            .projectId(projectId)
                            .build();
                    pipelineMapper.insert(basicInformation);
                    final JSONArray placemarks = JSONArray.from(value);
                    for (Object placemark : placemarks) {
                        final JSONObject jsonObject = JSONObject.from(placemark);
                        dealPlacemark(jsonObject, basicInformation.getId(), projectId, userId, placemarkCountTotal, count);
                    }
                } else {
                    dealPlacemark(JSONObject.from(value), parentId, projectId, userId, placemarkCountTotal, count);
                }
            }
        }
    }

    private void dealPlacemark(JSONObject placemark, Integer parentId, Integer projectId, Integer userId, Integer placemarkCountTotal, AtomicInteger count) {
        String name = placemark.getString("name");
        String description = placemark.getString("description");
        final JSONObject style = placemark.getJSONObject("Style");
        final JSONObject lineString = placemark.getJSONObject("LineString");

        int nameMaxLength = 50;
        int descriptionMaxLength = 2048;
        final boolean isValidName = !(name == null || "".equals(name) || name.length() >= nameMaxLength);
        final boolean isValidDesc = !(description == null || "".equals(description) || description.length() >= descriptionMaxLength);

        if (lineString != null) {
            final Integer i = count.incrementAndGet();
            log.info(i + "-" + name + "-" + placemark.keySet());
            if (!isValidName && name != null && name.length() >= nameMaxLength) {
                log.error(name + " -> " + "名称文字过长[{}], 已丢弃", name.length());
            }
            if (description != null) {
                description = description.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
            }
            if (!isValidDesc && description != null && description.length() >= descriptionMaxLength) {
                log.error(name + " -> " + "描述文字过长[{}], 已丢弃", description.length());
            }
            String coordinates = lineString.getString("coordinates");
            List<PipelinePoint> pointList = new ArrayList<>();
            coordinates = coordinates.replaceAll("\\n", " ");
            final String[] points = coordinates.split(" ");
            for (int i1 = 0; i1 < points.length; i1++) {
                final String[] point1 = points[i1].split(",");
                final String lng = point1[0];
                final String lat = point1[1];
                final String alt = point1[2];
                pointList.add(PipelinePoint.builder().seq(i1 + 1).lng(Double.valueOf(lng)).lat(Double.valueOf(lat)).alt(Float.valueOf(alt)).build());
            }
            final Pipeline pipeline = Pipeline.builder()
                    .type(0)
                    .parentId(parentId)
                    .name((name == null || "".equals(name)) ? "未命名Line" : name)
                    .projectId(projectId)
                    .build();
            if (style != null) {
                final JSONObject lineStyle = style.getJSONObject("LineStyle");
                if (lineStyle != null) {
                    final String color = lineStyle.getString("color");
                    final Integer width = lineStyle.getInteger("width");
                    if (color != null) {
                        pipeline.setColor(color.startsWith("#") ? color : "#" + color);
                    }
                    if (width != null) {
                        pipeline.setWide(width);
                    }
                }
            }
            if (isValidDesc) {
                pipeline.setDescription(description);
            }
            PipelinePoint centerPoint = pointList.get(pointList.size() / 2);
            pipeline.setCenterPoint("[" + centerPoint.getLng() + "," + centerPoint.getLat() + "]");
            final String pointsUrl = dealPipelineGetUrl(projectId, pointList, centerPoint);
            pipeline.setPointsUrl(pointsUrl);
            pipelineMapper.insert(pipeline);
            pipelinePointsInsert(pointList, pipeline.getId());
            webSocketService.sendUserKmlLoadMessage(JSONObject.from(WebSocketRo.builder().state(RoState.WEBSOCKET_SUCCESS.getValue())
                    .messageType(WebSocketMessageType.KML_LOAD_PROCESS.getValue())
                    .content(JSONObject.of("placemarkCountTotal", placemarkCountTotal,
                            "current", count.get(),
                            "percent", (count.get() * 100 / placemarkCountTotal))).build()), projectId, userId);
        }
    }


    @SneakyThrows
    public String dealPipelineGetUrl(Integer projectId, List<PipelinePoint> pointList, PipelinePoint centerPoint) {
        if (Objects.isNull(pointList) || pointList.size() == 0) {
            return null;
        }
        com.tianyu.inspection.common.protobuf.Pipeline.DataList.Builder dataListBuilder = com.tianyu.inspection.common.protobuf.Pipeline.DataList.newBuilder();
        pointList.forEach(point -> {
            com.tianyu.inspection.common.protobuf.Pipeline.Point.Builder dataBuilder = com.tianyu.inspection.common.protobuf.Pipeline.Point.newBuilder();
            dataBuilder.setLat(point.getLat());
            dataBuilder.setLng(point.getLng());
            if (Objects.nonNull(point.getAlt())) {
                dataBuilder.setAlt(point.getAlt());
            } else {
                dataBuilder.setAlt(0);
            }
            if (Objects.nonNull(point.getSeq())) {
                dataBuilder.setSeq(point.getSeq());
            }
            dataListBuilder.addPoint(dataBuilder.build());
        });
        dataListBuilder.setCenterLng(centerPoint.getLng());
        dataListBuilder.setCenterLat(centerPoint.getLat());
        String filePath = projectId + "/pipeline/" + UUID.randomUUID() + ".pb";
        final boolean success = ocsSimpleModel.putObject(filePath, dataListBuilder.build().toByteArray());
        if (!success) {
            log.info("reSaveFile[{}]", filePath);
            Thread.sleep(300);
            ocsSimpleModel.putObject(filePath, dataListBuilder.build().toByteArray());
        }
        final OcsObject object = ocsSimpleModel.getObject(filePath);
        UploadFile uploadFile = new UploadFile()
                .setUrl("/" + filePath)
                .setProjectId(projectId)
                .setSize(object != null ? (long) Math.toIntExact(object.getContentLength()) : null)
                .setType("application/octet-stream")
                .setCategory(FileTypeEnum.FILE_PIPELINE_PB.getValue());
        if (1 != uploadFileMapper.insert(uploadFile)) {
            ocsSimpleModel.deleteObject(filePath);
            return null;
        } else {
            return "/" + filePath;
        }
    }

    /**
     * 通过ID等参数查询一条数据
     *
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态等]
     * @return 单条记录结果
     */
    @Override
    public Pipeline selectOne(QueryMo queryMo) {
        if (Objects.nonNull(queryMo.getEqMap().get("id"))) {
            Pipeline pipeline = pipelineMapper.selectOne(new QueryWrapper<Pipeline>().allEq(queryMo.getEqMap()));
            if (Objects.nonNull(pipeline)) {
                String pointsUrl = pipeline.getPointsUrl();
                if (Objects.nonNull(pointsUrl)) {
                    pipeline.setPointsUrl(ocsSimpleModel.getObjectUrl(pointsUrl));
                }
            }
            return pipeline;
        }
        return null;
    }


    @Override
    public Pipeline selectOneDetails(QueryMo queryMo) {
        if (Objects.nonNull(queryMo.getEqMap().get("id"))) {
            Pipeline pipeline = pipelineMapper.selectOne(new QueryWrapper<Pipeline>().allEq(queryMo.getEqMap()));
            if (Objects.nonNull(pipeline)) {
                pipeline.setPointsUrl(null);
                String redisKey = appConstants.redisPipeline + pipeline.getProjectId() + ":" + pipeline.getName() + "[" + pipeline.getId() + "]";
                Object object = valueOperations.get(redisKey);
                if (Objects.nonNull(object)) {
                    pipeline.setPoints(object);
                    JSONArray jsonArray = new ObjectMapper().convertValue(object, JSONArray.class);
                    pipeline.setPointsCount(jsonArray.size());
                } else {
                    Integer pipelineId = pipeline.getId();
                    QueryMo queryMo1 = new QueryMo();
                    queryMo1.put("pipelineId", pipelineId);
                    queryMo1.build(PipelinePoint.class, null);
                    List<PipelinePoint> pipelinePoints = pipelinePointMapper.selectList(new QueryWrapper<PipelinePoint>().allEq(queryMo1.getEqMap()));
                    pipeline.setPoints(pipelinePoints);
                    pipeline.setPointsCount(pipelinePoints.size());
                    valueOperations.set(redisKey, pipelinePoints, 7, TimeUnit.DAYS);
                    setOperations.add(appConstants.redisPipeline, redisKey);
                }
            }
            return pipeline;
        }
        return null;
    }

    /**
     * 插入一条数据
     *
     * @param operateMo 实体对象
     * @return 是否操作成功
     */
    @Override
    public boolean insert(OperateMo operateMo) {
        ObjectMapper objectMapper = new ObjectMapper();
        Pipeline pipeline = objectMapper.convertValue(operateMo.getEntity(), Pipeline.class);
        return 1 == pipelineMapper.insert(pipeline);
    }

    /**
     * 通过ID删除一条数据
     *
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态等]
     * @return 是否操作成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public ModelMap deleteOne(QueryMo queryMo) {
        ModelMap modelMap = new ModelMap();
        modelMap.put("isDbHasRecord", false);
        modelMap.put("isDbPipelineDelete", false);
        modelMap.put("isOssFileDelete", false);
        if (Objects.nonNull(queryMo.getEqMap().get("id"))) {
            Pipeline pipeline = pipelineMapper.selectOne(new QueryWrapper<Pipeline>().allEq(queryMo.getEqMap()));
            if (Objects.nonNull(pipeline)) {
                modelMap.put("isDbHasRecord", true);
                Constants.EXECUTOR.execute(() -> {
                    if (pipeline.getType() == 1) {
                        deleteChildren(pipeline.getId(), queryMo.getInteger("projectId"));
                    }
                    log.info("delete line[{}]", pipeline.getId());
                });
            } else {
                return modelMap;
            }
            if (1 == pipelineMapper.delete(new QueryWrapper<Pipeline>().allEq(queryMo.getEqMap()))) {
                modelMap.put("isDbPipelineDelete", true);
                if (pipeline.getType() == 0 && ocsSimpleModel.deleteObject(pipeline.getPointsUrl().substring(1))) {
                    modelMap.put("isOssFileDelete", true);
                }
            }
        }
        return modelMap;
    }

    private void deleteChildren(Integer parentId, Integer projectId) {
        final List<Pipeline> children = pipelineMapper.selectList(Wrappers.<Pipeline>lambdaQuery()
                .eq(Pipeline::getParentId, parentId)
                .eq(Pipeline::getProjectId, projectId));
        for (Pipeline child : children) {
            final Integer id = child.getId();
            if (child.getType() == 1) {
                deleteChildren(id, projectId);
                pipelineMapper.deleteById(id);
            } else {
                pipelineMapper.deleteById(id);
            }
            log.info("delete line[{}]", id);
        }
    }

    /**
     * 插入一条数据
     *
     * @param operateMo 更新参数集
     * @return ModelMap
     */
    @Override
    public boolean update(OperateMo operateMo) {
        ObjectMapper objectMapper = new ObjectMapper();
        Pipeline pipeline = objectMapper.convertValue(operateMo.getEntity(), Pipeline.class);
        return 1 == pipelineMapper.update(pipeline, new QueryWrapper<Pipeline>().allEq(operateMo.getEqMap()));
    }

    /**
     * 通过ID逻辑删除一条数据
     *
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态]
     * @return 是否操作成功
     */
    @Override
    public boolean logicallyDelete(QueryMo queryMo) {
        return 1 == pipelineMapper.update(
                new Pipeline().setState(1),
                new QueryWrapper<Pipeline>().allEq(queryMo.getEqMap())
        );
    }
}
